
#include "Anim.h"
#include "SkeletonMesh.h"
#include "IFile.h"
#include "Model.h"

BOOL _Anim::SetEventFlag(const _AniEventType& eType,const _AniEventFLag& eFlag)
{
	BOOL bResult = FALSE;
	_AnimEvent* pEvent = NULL;
	GPOS pos = m_listEvent;
	while (pos)
	{
		pEvent = m_listEvent.GetNext(pos);
		if (pEvent->m_byEventType == eType)
		{
			pEvent->m_byFlag = eFlag;	
			bResult = TRUE;
		}
	}
	return bResult;
}
_AnimEvent* _Anim::UpdateEvent(const float& fTime)
{
	_AnimEvent* pEvent = NULL;
	GPOS pos = m_listEvent;
	while (pos)
	{
		pEvent = m_listEvent.GetNext(pos);
		if (pEvent->m_byFlag == _FLAG_ANI_1)
		{
			if (pEvent->m_fTime<fTime)
			{
				pEvent->m_byFlag = _FLAG_ANI_0;
				return pEvent;
			}			
		}
	}
	return NULL;
}
//-------------------------------------------------------
void _FrameNode::ResetAnim(const BOOL& bResetMat)
{
	m_uCurrPosKey = 0;
	m_uCurrRotKey = 0;

	if (bResetMat)
	{
		m_matAnim = m_matOrg;
	}

	_FrameNode* pChild = NULL;
	GPOS pos = m_Children;
	while (pos)
	{
		pChild = m_Children.GetNext(pos);
		pChild->ResetAnim(bResetMat);
	}
}

void _FrameNode::UpdateAnim(const float& fTime)
{
	D3DXMATRIX matRot,matPos;
	float fLerpValue;
	float fDetaTime;	
	float fStepTime;

	BOOL bAnim   = FALSE;

	D3DXVECTOR3 vPos;
	D3DXQUATERNION quat;

	D3DXMatrixIdentity(&matRot);
	D3DXMatrixIdentity(&matPos);	

	_RotateKey* pCurrRotKey = m_pParentFram->GetRotKey(m_uBoneID,m_uCurrRotKey);

	if (pCurrRotKey)
	{	
		bAnim = TRUE;
		_RotateKey* pNextRotKey = m_pParentFram->GetRotKey(m_uBoneID,m_uCurrRotKey+1);	
		while(pNextRotKey)
		{			
			if (pNextRotKey->fTime>fTime)
			{
				break;
			}
			else
			{
				m_uCurrRotKey++;
				pNextRotKey = m_pParentFram->GetRotKey(m_uBoneID,m_uCurrRotKey+1);
			}	
		}			

		if (pNextRotKey)
		{
			pCurrRotKey = pNextRotKey-1;
			fDetaTime = fTime - pCurrRotKey->fTime;	
			fStepTime  = pNextRotKey->fTime - pCurrRotKey->fTime;				
			fLerpValue = fStepTime>0.0f  ? (fDetaTime/ fStepTime) : 0.0f;
			D3DXQuaternionSlerp(&quat,&pCurrRotKey->quat,&pNextRotKey->quat,fLerpValue);						
		}
		else
		{
			pCurrRotKey = m_pParentFram->GetRotKey(m_uBoneID,m_uCurrRotKey);
			quat = pCurrRotKey->quat;
		}

		quat.w=-quat.w;	
		D3DXMatrixRotationQuaternion(&matRot, &quat);
	}

	_PosKey* pCurrPosKey = m_pParentFram->GetPosKey(m_uBoneID,m_uCurrPosKey);
	if (pCurrPosKey)
	{		
		_PosKey* pNextPosKey = m_pParentFram->GetPosKey(m_uBoneID,m_uCurrPosKey+1);	
		while(pNextPosKey)
		{			
			if (pNextPosKey->fTime>fTime)
			{
				break;
			}
			else
			{
				m_uCurrPosKey++;
				pNextPosKey = m_pParentFram->GetPosKey(m_uBoneID,m_uCurrPosKey+1);
			}	
		}

		if (pNextPosKey)
		{
			pCurrPosKey  = pNextPosKey - 1;			
			fDetaTime  = fTime - pCurrPosKey->fTime;	
			fStepTime  = pNextPosKey->fTime - pCurrPosKey->fTime;
			fLerpValue = fDetaTime>0.0f  ? (fDetaTime / fStepTime) : 0.0f;
			D3DXVec3Lerp(&vPos,&pCurrPosKey->vPos,&pNextPosKey->vPos,fLerpValue);
		}
		else
		{
			pCurrPosKey = m_pParentFram->GetPosKey(m_uBoneID,m_uCurrPosKey);
			vPos = pCurrPosKey->vPos;
		}

		D3DXMatrixTranslation(&matPos, vPos.x, vPos.y, vPos.z);

		if(!bAnim)
		{
			bAnim = TRUE;
			matRot = m_matAnim;
			matRot._41 = matRot._42 = matRot._43 = 0;
		}		

	}
	else
	{
		if (bAnim)
		{
			D3DXMatrixTranslation(&matPos, m_matAnim._41, m_matAnim._42, m_matAnim._43);
		}		
	}

	if (bAnim)
	{
		D3DXMatrixMultiply(&m_matAnim, &matRot, &matPos);
	}

	_FrameNode* pChildFrameNode = NULL;
	GPOS pos = m_Children;
	while (pos)
	{
		pChildFrameNode = m_Children.GetNext(pos);
		pChildFrameNode->UpdateAnim(fTime);
	}
}
void _FrameNode::UpdateChildFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn)
{
	_FrameNode* pChildFrameNode = NULL;
	GPOS pos = m_Children;
	while (pos)
	{
		pChildFrameNode = m_Children.GetNext(pos);
		pChildFrameNode->UpdateFrame(pMesh,pmatIn);
	}
}
void _FrameNode::UpdateFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn)
{
	D3DXMATRIX* pMatOut = pMesh->GetMatCombine(m_uBoneID);
	if (m_fRotY!=0.0f)
	{
		D3DXMATRIX matR;
		D3DXMATRIX matOR = m_matAnim;
		matOR._41 = matOR._42 = matOR._43 = 0.0f;
		D3DXMatrixRotationY(&matR,m_fRotY);
		matR=matR*matOR;
		matR._41 = m_matAnim._41;
		matR._42 = m_matAnim._42;
		matR._43 = m_matAnim._43;

		D3DXMatrixMultiply(pMatOut, &matR,pmatIn);
	}
	else 
	{
		D3DXMatrixMultiply(pMatOut, &m_matAnim,pmatIn);
	}

	if (!pMesh->GetParentModel()->IsVisual())
	{
		return;
	}

	_FrameNode* pChildFrameNode = NULL;
	GPOS pos = m_Children;
	while (pos)
	{
		pChildFrameNode = m_Children.GetNext(pos);
		pChildFrameNode->UpdateFrame(pMesh,pMatOut);
	}

}

void _FrameNode::UpdateChildShadowFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn)
{
	_FrameNode* pChildFrameNode = NULL;
	GPOS pos = m_Children;
	while (pos)
	{
		pChildFrameNode = m_Children.GetNext(pos);
		pChildFrameNode->UpdateShadowFrame(pMesh,pmatIn);
	}
}

void _FrameNode::UpdateShadowFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn)
{
	D3DXMATRIX* pMatOut = pMesh->GetMatCombine(m_uBoneID);
	if (m_fRotY!=0.0f)
	{
		D3DXMATRIX matR;
		D3DXMATRIX matOR = m_matAnim;
		matOR._41 = matOR._42 = matOR._43 = 0.0f;
		D3DXMatrixRotationY(&matR,m_fRotY);
		matR=matR*matOR;
		matR._41 = m_matAnim._41;
		matR._42 = m_matAnim._42;
		matR._43 = m_matAnim._43;

		D3DXMatrixMultiply(pMatOut, &matR,pmatIn);
	}
	else 
	{
		D3DXMatrixMultiply(pMatOut, &m_matAnim,pmatIn);
	}

	D3DXVECTOR4 vec4Out;
	D3DXVECTOR3 vec3Cur=D3DXVECTOR3(pMatOut->_41,pMatOut->_42,pMatOut->_43);

	D3DXVec3Transform( &vec4Out, &vec3Cur, pmatIn );
	pMesh->GetParentModel()->SetShadowMaxX((float)fabs(vec4Out.x/vec4Out.z));
	pMesh->GetParentModel()->SetShadowMaxX((float)fabs(vec4Out.y/vec4Out.z));

	_FrameNode* pChildFrameNode = NULL;
	GPOS pos = m_Children;
	while (pos)
	{
		pChildFrameNode = m_Children.GetNext(pos);
		pChildFrameNode->UpdateFrame(pMesh,pMatOut);
	}

}
//-------------------------------------------------------------------------------------------
void _Frame::CheckFrame(const float& fTime)
{
	if (!m_pAnim)
	{
		return;
	}
	m_fCurrTime += fTime * m_fVelocity;
	_AnimEvent* pEvent = m_pAnim->UpdateEvent(m_fCurrTime);
	if (pEvent)
	{
		m_pSkelMesh->GetParentModel()->RunAnimEvent(pEvent);
	}

	if (m_fCurrTime>m_pAnim->m_uMaxTime && m_iAniPlayOption != _NotLoop)
	{
		m_fCurrTime = m_fCurrTime - m_pAnim->m_uMaxTime + m_pAnim->GetBlend();
		ResetAnim(FALSE);
		m_bRestartFirstFrame = TRUE;
	}
}

void _Frame::Update(const D3DXMATRIX* pmatIN)
{
	if (m_pAnim)
	{
		float fDeta = 0.0f;
		if (m_pSkelMesh->GetType() == _SMESH_GENERAL)
		{
			if (m_bRestartFirstFrame)
			{		
				_AnimKeyList* pKeyList = &m_pAnim->m_pAnimKeyList[m_RootFrameNode.GetBonID()];
				_PosKey*  pPosKey = pKeyList->GetEndPosKey();
				if (pPosKey)
				{
					fDeta = fabs(pPosKey->vPos.z - m_fLastPosZ);
				}	

				m_bRestartFirstFrame = FALSE;
			}
			else
			{
				fDeta = m_fLastPosZ;
			}
		}

		m_RootFrameNode.UpdateAnim(m_fCurrTime);

		if (m_pSkelMesh->GetType() == _SMESH_GENERAL)
		{
			const float fPosZ = m_RootFrameNode.m_matAnim._43;
			m_pSkelMesh->SetDistance(fPosZ-fDeta);

			m_fLastPosZ = fPosZ;
			if(m_iAniPlayOption == _PlayOpt0)
			{
				m_RootFrameNode.m_matAnim._43 = 0.0f;
			}
		}

	}

	if (m_pSkelMesh->GetType() == _SMESH_GENERAL)
	{
		m_RootFrameNode.UpdateFrame(m_pSkelMesh,pmatIN);
	}
	else
	{
		m_pSkelMesh->SetMatCombine(0,*pmatIN);
		m_RootFrameNode.UpdateChildFrame(m_pSkelMesh,pmatIN);
	}	
}

void _Frame::UpdateShadow(const D3DXMATRIX* pmatIN)
{
	if (m_pSkelMesh->GetType() == _SMESH_GENERAL)
	{
		m_RootFrameNode.UpdateShadowFrame(m_pSkelMesh,pmatIN);
	}
	else
	{
		m_pSkelMesh->SetMatCombine(0,*pmatIN);
		m_RootFrameNode.UpdateChildShadowFrame(m_pSkelMesh,pmatIN);
	}	
}

void _Frame::SetAnim(_Anim* pAnim,const BOOL& bReset)
{
	m_fCurrTime = 0.0f;
	if (m_pAnim == pAnim)
	{
		ResetAnim(bReset);
	}
	else
	{
		m_fVelocity = pAnim->GetFPS()*FPSMOD;
		if (bReset)
		{
			m_fLastPosZ = 0.0f;
			m_bRestartFirstFrame = FALSE;
		}
		m_pAnim = pAnim;
		ResetAnim(pAnim == NULL&bReset);
	}


}

void _Frame::ResetAnim(const BOOL& bRestMat)
{
	m_RootFrameNode.ResetAnim(m_pAnim == NULL & bRestMat);
}
